home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Developer
/
BBFig
/
Source
/
YapOutput.m
< prev
next >
Wrap
Text File
|
1992-05-13
|
9KB
|
334 lines
/*
* YapOutput.m
* Author: Ali Ozer
* Created: Mar 6, 1989
* Modified: Jun & Jul 1989 for 1.0. Added NX_HANDLER for error detection.
* Modified: Aug 90 for 2.0. Added use of second context for robustness.
* Modified: Jan 92 for BBFig by Izumi Ohzawa (izumi@pinoko.berkeley.edu)
*
* This class is a subclass of view that manages the output in Yap. It
* provides a method (executeCodeFrom:) to execute PS from a text object.
* The PostScript output will be displayed in the view. The output is
* also cached in a bitmap for fast redraw response.
*
* You may freely copy, distribute and reuse the code in this example.
* NeXT disclaims any warranty of any kind, expressed or implied,
* as to its fitness for any particular use.
*/
#import "YapOutput.h"
#import "YapApp.h"
#import "YapWrap.h" // Generated from YapWrap.psw
#import "BBox.h" // Generated from BBox.psw
#import <appkit/nextstd.h>
#import <appkit/Panel.h>
#import <appkit/Text.h>
#import <appkit/Window.h>
#import <dpsclient/wraps.h>
#import <objc/error.h>
#import <streams/streams.h>
#import <libc.h>
#import <string.h>
#import <defaults.h>
#import <sys/file.h>
#import <stdio.h>
@implementation YapOutput
/*
* initFrame: initializes the instance and creates a cache.
*/
- initFrame:(const NXRect *)viewFrame
{
[super initFrame:viewFrame];
[self setCacheCleared:YES];
[self setCacheShown:NO];
[self setMeshON:YES];
[self setFigureBB:YES];
cache = [[Window allocFromZone:[self zone]]
initContent:&bounds
style:NX_PLAINSTYLE
backing:NX_RETAINED
buttonMask:0
defer:NO];
return self;
}
/*
* Set/get parameters that determine behaviour.
*/
- (BOOL)isCacheCleared
{
return clearCache;
}
- (BOOL)isCacheShown
{
return showCache;
}
- (BOOL)isMeshON
{
return meshON;
}
- (BOOL)isFigureBB
{
return figureBB;
}
- setCacheCleared:(BOOL)flag
{
clearCache = flag;
return self;
}
- setCacheShown:(BOOL)flag
{
showCache = flag;
return self;
}
- setMeshON:(BOOL)flag
{
meshON = flag;
return self;
}
- setFigureBB:(BOOL)flag
{
figureBB = flag;
return self;
}
/*
* sizeTo:: is called whenever the view is resized. It resizes the bitmap cache
* along with the view. It doesn't do anything if the new size is equal to the
* old one.
*/
- sizeTo:(NXCoord)width :(NXCoord)height
{
if (width == frame.size.width && height == frame.size.height) return self;
[super sizeTo:width :height];
[cache sizeWindow:width :height];
return self;
}
/*
* drawSelf: simply shows the cache.
*/
- drawSelf:(NXRect *)rects :(int)rectCount
{
if (rectCount == 3) { /* Scrolling diagonally; use last two rectangles */
rects++;
PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects),
[cache gState], NX_X(rects), NX_Y(rects), NX_COPY);
rects++;
PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects),
[cache gState], NX_X(rects), NX_Y(rects), NX_COPY);
} else {
PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects),
[cache gState], NX_X(rects), NX_Y(rects), NX_COPY);
}
return self;
}
- free
{
[cache free];
return [super free];
}
/*
* Ugly function to write PostScript error.
*/
void WritePostScriptError (char *errStr, int errStrLength, NXHandler *errorState)
{
char *streamAddr;
int streamLength, maxLength;
NXStream *errorStream;
if ((errorState->code == dps_err_ps) &&
(errorStream = NXOpenMemory (NULL, 0, NX_WRITEONLY))) {
DPSPrintErrorToStream (errorStream, (DPSBinObjSeq)(errorState->data2));
NXFlush (errorStream);
NXGetMemoryBuffer (errorStream, &streamAddr, &streamLength, &maxLength);
if (streamLength > errStrLength-1) streamLength = errStrLength-1;
strncpy (errStr, streamAddr, streamLength);
errStr[streamLength] = 0;
NXCloseMemory (errorStream, NX_FREEBUFFER);
} else {
sprintf (errStr, "A non-PostScript error while running program.");
}
}
/*
* SwitchContextsWithFocus() will make the specified context the current
* context and make it focus on the same area the old context was
* focused on.
*/
static void SwitchContextsWithFocus (DPSContext newContext)
{
float c1x, c1y, c2x, c2y;
float winCTM[6];
int realWinNum;
GetFocus (&c1x, &c1y, &c2x, &c2y, winCTM, &realWinNum);
DPSSetContext (newContext);
ReFocus (realWinNum, winCTM, c1x, c1y, c2x, c2y);
}
#define STATUSLENGTH 200 // Some large number for error string length
/*
* executeCodeFrom: treats the contents of the specified text object as
* a PostScript program and executes it. The code is copied from the
* text object into a memory stream and then sent to the server using
* DPSWriteData().
*
* For protection against errors, the PostScript code is interpreted in a
* context separate from the Application's own context (which is created
* in the +new method of Application). We first focus on the cache,
* note the various parameters (global window number, the transformation
* matrix, and the clip path), and then switch to the alternate context and
* reapply the parameters to establish a focus on the same area.
*
* Protection against PostScript errors is provided through the use of
* NX_DURING/NX_HANDLER. If an error occurs, we immediately blast the
* second context and report the first error encountered. If no errors
* occur during the execution, then we hang on to the context as it can
* be reused.
*
* Note that the NXEPSImageRep class provides a similar (but more powerful)
* sort of functionality for EPS files. Use that class rather than the code
* here if you wish to make use of EPS files in your application. This code
* here is meant for unstructured, short pieces of PostScript code,
* eactly the kind that Yap encounters...
*/
- executeCodeFrom:textObj andReturnBB: (float *)llx : (float *)lly
: (float *)urx : (float *)ury
usertime: (int *) utime
{
// int utime; /* Time taken to execute the code */
char status[STATUSLENGTH]; /* Array for error messages */
NXStream *psStream; /* Memory stream for the PostScript */
char *psBuffer; /* The buffer used by the stream */
int psLen; /* And the length of this buffer */
static DPSContext yapContext = NULL; /* The second context */
DPSContext curContext = DPSGetCurrentContext();
NXHandler exception;
/* Order front output window */
[[self window] orderFront:self];
/* Open a memory stream and write the text into it... */
if (psStream = NXOpenMemory (NULL, 0, NX_WRITEONLY)) {
int dummy;
NXPrintf (psStream, "/yaptime usertime def "
"/-showpage {} def\n");
[textObj writeText:psStream];
NXPrintf (psStream, "\n/yaptime usertime yaptime sub def\n");
NXFlush (psStream);
NXGetMemoryBuffer (psStream, &psBuffer, &psLen, &dummy);
} else {
[[self window] setTitle:"Can't open memory stream!"];
return self;
}
[[self window] setTitle:"BUSY"];
/* Lock focus on the cache. If user wishes to see the cache, bring it up. */
[[cache contentView] lockFocus];
if (clearCache) NXEraseRect (&bounds);
if (showCache) [[cache center] orderFront:self];
/* Create the second context if it needs to be created. */
if (yapContext == NULL) {
const char *app = [NXApp appName];
yapContext = DPSCreateContext(NXGetDefaultValue(app, "NXHost"),
NXGetDefaultValue(app, "NXPSName"),
NULL, NULL);
DPSSetContext (curContext);
}
/* Focus the second context to whatever the first context is focused on. */
SwitchContextsWithFocus (yapContext);
/* This will let us know if there were any errors. */
exception.code = 0;
NX_DURING {
DPSPrintf(yapContext, "/yapwidth %f def /yapheight %f def\n",
bounds.size.width, bounds.size.height);
if(meshON)
ShowMesh(); /* draws point grid */
if(figureBB)
SendBBfig(); /* pswrap func containing bbfig */
DPSWriteData(yapContext, psBuffer, psLen);
NXPing(); /* This does not return until the execution is done. */
/* If there were any errors, we jump to the handler. */
GetUserTime (utime); /* utime already pointer */
sprintf (status, "BBFig Postscript Output (Execution Time %d ms)", *utime);
if(figureBB)
GetBBox(llx, lly, urx, ury); /* get BoundingBox; args are pointers */
else
{
*llx = *lly = 0.0;
*urx = *ury = 999.0;
*utime = -1;
}
/*
sprintf (status, "%%%%BoundingBox: %5.0f %5.0f %5.0f %5.0f",
*llx, *lly, *urx, *ury);
*/
} NX_HANDLER {
exception = NXLocalHandler; /* Make note of the error... */
} NX_ENDHANDLER
/* Switch back to the app context. */
DPSSetContext(curContext);
/* In case of error, report it and blow the second context away. */
/* -> Destroy the second context anyway */
DPSDestroyContext(yapContext);
yapContext = NULL;
if (exception.code != 0) {
// DPSDestroyContext(yapContext);
// yapContext = NULL;
WritePostScriptError (status, STATUSLENGTH, &exception);
*llx = *lly = 0.0;
*urx = *ury = 999.0;
*utime = -1; /* error indication */
}
if (showCache) [cache orderOut:self];
[[cache contentView] unlockFocus];
[self display];
[[self window] setTitle:status];
NXCloseMemory (psStream, NX_FREEBUFFER);
return self;
}
@end